// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`define SAMPLE_CSR_OFFSET       16'h0010
`define SEQ_CSR_ADDR            16'h0000
`define SAMPLE_CSR_LOW          16'h0010
`define SAMPLE_CSR_HIGH         16'h0030
		
module adc_wrapper
(
// ------------------------
// Clock and Reset signals
// ------------------------
   input       iClk,                                        //clock for sequential logic 
   input       iRst_n,                                      //reset signal from PLL Lock, resets state machine to initial state
   
   input       isys_clk,                                    //system clock
   input       isys_rst_n,                                  //reset signal from PLL Lock, resets state machine to initial state
// ----------------------------
// inputs and outputs
// ----------------------------
   //ADC realted
   input 	         iclk_2m_adc,
   input             iadc_pll_locked,

   //AVMM interface 
   input      [31:0] avmm_address,
   input             avmm_write,
   input      [31:0] avmm_writedata,          
   input             avmm_read,     
   output     [31:0] avmm_readdata,      
   output            avmm_readdatavalid, 
   output            avmm_waitrequest,           
   input      [ 3:0] avmm_byteenable,
	
	//error report
	output            invalid_access

);


////////////////////////////////////////////////////////////
//Internal signals
////////////////////////////////////////////////////////////
   localparam        LOW  = 1'b0;
	localparam        HIGH = 1'b1;
	
   //AVMM ADC interface 
    wire    [31:0]    avmm_adc_address          ;
    wire              avmm_adc_write            ;
    wire    [31:0]    avmm_adc_writedata        ;          
    wire              avmm_adc_read             ;     
    reg     [31:0]    avmm_adc_readdata         ;      
    reg               avmm_adc_readdatavalid    ; 
    wire              avmm_adc_waitrequest      ;           
    wire    [ 3:0]    avmm_adc_byteenable       ;
   
	reg               sequencer_csr_address;
	reg               sequencer_csr_read;
	reg               sequencer_csr_write;
	wire [31:0]       sequencer_csr_writedata;
	wire [31:0]       sequencer_csr_readdata;
	
	reg  [6:0]        sample_store_csr_address;   // sample_store_csr.address
	reg               sample_store_csr_read;      //                 .read
	reg               sample_store_csr_write;     //                 .write
	wire [31:0]       sample_store_csr_writedata; //                 .writedata
	wire [31:0]       sample_store_csr_readdata;  //                 .readdata
	wire              sample_store_irq_irq;
	
	
	
	
	wire [15:0]       addr_local;                              //Only 16 bits out of 32 bits avmm_adc_address supported
	reg  [1:0]        cs;
	reg  [1:0]        cs_latch;
	
	wire              seq_csr_addr_range;
	wire              sam_csr_addr_range;
	
	reg               avmm_readdatavalid_seq_csr;
	reg               avmm_readdatavalid_sam_csr;
	reg               avmm_readdatavalid_sam_csr_r;
	reg               avmm_readdatavalid_seq_csr_r;
	
	reg               invalid_read;
	reg               invalid_write;
	

////////////////////////////////////////////////////////////
//Combinational Logic
////////////////////////////////////////////////////////////

   assign avmm_adc_waitrequest            = 1'b0;                            //Fix wait request to 1'b0 as no wait needed

   assign addr_local                  = avmm_adc_address[15:0];
	
	//pass input writedata & byteenable signals from master port to each slave ports directly
   assign sample_store_csr_writedata  = avmm_adc_writedata;

   assign sequencer_csr_writedata     = avmm_adc_writedata;
	
	assign seq_csr_addr_range          = (addr_local == `SEQ_CSR_ADDR);
	
	assign sam_csr_addr_range          = (addr_local >= `SAMPLE_CSR_LOW && addr_local <= `SAMPLE_CSR_HIGH);
	
	assign invalid_access              = invalid_read || invalid_write;


////////////////////////////////////////////////////////////
//AVMM CDC
////////////////////////////////////////////////////////////
altera_avalon_mm_clock_crossing_bridge #(
    .DATA_WIDTH            (32  )
   ,.SYMBOL_WIDTH          (8   )
   ,.HDL_ADDR_WIDTH        (32  )
   ,.BURSTCOUNT_WIDTH      (1   )

   ,.COMMAND_FIFO_DEPTH    (4   )
   ,.RESPONSE_FIFO_DEPTH   (4   )

   ,.MASTER_SYNC_DEPTH     (2   )
   ,.SLAVE_SYNC_DEPTH      (2   ))
crossing_bridge
(
    .s0_clk                 (isys_clk                   )   //input 
   ,.s0_reset               (~isys_rst_n                )   //input 
                      
   ,.m0_clk                 (iClk                       )   //input         
   ,.m0_reset               (~iRst_n                    )   //input       
                      
   ,.s0_waitrequest         (avmm_waitrequest           )   //output
   ,.s0_readdata            (avmm_readdata              )   //output   
   ,.s0_readdatavalid       (avmm_readdatavalid         )   //output
   ,.s0_burstcount          ('d1                        )   //input  
   ,.s0_writedata           (avmm_writedata             )   //input   
   ,.s0_address             (avmm_address               )   //input     
   ,.s0_write               (avmm_write                 )   //input       
   ,.s0_read                (avmm_read                  )   //input        
   ,.s0_byteenable		    (4'b1111                    )   //input  
   ,.s0_debugaccess		    (0                          )   //input 
                      
   ,.m0_waitrequest         (avmm_adc_waitrequest       )   //input 
   ,.m0_readdata            (avmm_adc_readdata          )   //input    
   ,.m0_readdatavalid       (avmm_adc_readdatavalid     )   //input 
   ,.m0_burstcount          (                           )   //output 
   ,.m0_writedata           (avmm_adc_writedata         )   //output  
   ,.m0_address             (avmm_adc_address           )   //output    
   ,.m0_write               (avmm_adc_write             )   //output      
   ,.m0_read                (avmm_adc_read              )   //output       
   ,.m0_byteenable          (avmm_adc_byteenable        )   //output 
   ,.m0_debugaccess         (                           )   //output
);

////////////////////////////////////////////////////////////
//Sequencial Logic for AVMM Read and Write
////////////////////////////////////////////////////////////

   always @ (*) begin
	   if(seq_csr_addr_range) begin
		   cs    = 2'b01;
		end
		else if (sam_csr_addr_range) begin
		   cs    = 2'b10;
		end
		else begin
		   cs    = 2'b00;
		end
	end
	
	always @ (posedge iClk or negedge iRst_n) begin
	   if (!iRst_n) begin
		   cs_latch    <= 2'b00;
		end
		else begin
		   if (avmm_adc_read) begin
			   cs_latch <= cs;
			end
			else begin
			   cs_latch <= cs_latch;
			end
		end
	end
	
	//handle invalid_read
	always @ (*) begin
	   if (avmm_adc_read && !( |avmm_adc_address[31:16]) && (&avmm_adc_byteenable)) begin
		   if ((addr_local == `SEQ_CSR_ADDR) || (addr_local >= `SAMPLE_CSR_LOW && addr_local <= `SAMPLE_CSR_HIGH)) begin
			   invalid_read      =   1'b0;
			end
			else begin
			   invalid_read      =   1'b1;
			end
		end
		else begin
		   invalid_read         =   1'b0;
		end
	end
	
	//handle invalid_write
	always @ (*) begin
	   if (avmm_adc_write && !( |avmm_adc_address[31:16]) && (&avmm_adc_byteenable)) begin
		   if ((addr_local == `SEQ_CSR_ADDR) && !(|avmm_adc_writedata[31:4])) begin
			   invalid_write     =   1'b0;    
			end
			else begin
			   invalid_write     =   1'b1;
			end
		end
		else begin
		   invalid_write        =   1'b0;
		end
	end
   
	//pass slave readdata to master according to address range.
   always @ (*) begin
      case ( cs_latch )
         2'b01   : avmm_adc_readdata  = sequencer_csr_readdata;
         2'b10   : avmm_adc_readdata  = sample_store_csr_readdata;
         default : avmm_adc_readdata  = 32'hFFFF_FFFF;
      endcase
   end 
	
	//pass relative addr from master to slave
	always @ (*) begin
	   case (cs)
		   2'b01   : begin
			   sequencer_csr_address      = 1'b0;    //access seq csr
				sample_store_csr_address   = 7'b0;
			end
			2'b10   : begin
			   sequencer_csr_address      = 1'b0;
				sample_store_csr_address   = (addr_local - `SAMPLE_CSR_OFFSET)>>2;   //access sample csr, align csr_address from byte align to DW align
			end
			default : begin
			   sequencer_csr_address      = 1'b0;    
				sample_store_csr_address   = 7'b0;
			end
		endcase
	end
	
	//pass write from master to slave
	always @ (*) begin
	   case (cs)
		   2'b01   : begin
			   sequencer_csr_write        = avmm_adc_write;
				sample_store_csr_write     = 1'b0;
			end
			2'b10   : begin
			   sequencer_csr_write        = 1'b0;
				sample_store_csr_write     = 1'b0;       //read only, not allow to write
			end
			default : begin
			   sequencer_csr_write        = 1'b0;
				sample_store_csr_write     = 1'b0;
			end
		endcase
	end
	
	//pass read from master to slave
	always @ (*) begin
	   case (cs)
		   2'b01   : begin
			   sequencer_csr_read         = avmm_adc_read;
				sample_store_csr_read      = 1'b0;
			end
			2'b10   : begin
			   sequencer_csr_read         = 1'b0;
				sample_store_csr_read      = avmm_adc_read; 				
			end
			default : begin
			   sequencer_csr_read         = 1'b0;
				sample_store_csr_read      = 1'b0;
			end
		endcase
	end
	
   //decide which readdatavalid should be the output
	always @ (*) begin
	   if(avmm_readdatavalid_seq_csr && !avmm_readdatavalid_sam_csr) begin
		   avmm_adc_readdatavalid            = 1'b1;
		end
		else if(avmm_readdatavalid_sam_csr_r && !avmm_readdatavalid_seq_csr_r) begin
		   avmm_adc_readdatavalid            = 1'b1;
		end
		else begin
		   avmm_adc_readdatavalid            = 1'b0;
		end
	end
	
	//response avmm_adc_readdatavalid
	always @ (posedge iClk or negedge iRst_n) begin
      if(!iRst_n) begin
	      avmm_readdatavalid_sam_csr_r <= 1'b0;
			avmm_readdatavalid_seq_csr_r <= 1'b0;
	   end
	  
	   else begin
	      avmm_readdatavalid_sam_csr_r <= avmm_readdatavalid_sam_csr;
			avmm_readdatavalid_seq_csr_r <= avmm_readdatavalid_seq_csr;
	   end
   end	
	
	always @ (posedge iClk or negedge iRst_n) begin
      if(!iRst_n) begin
		   avmm_readdatavalid_sam_csr         <= 1'b0;
	   end
	  
	   else begin
	      if (avmm_adc_read && (&avmm_adc_byteenable) && sam_csr_addr_range) begin
			   avmm_readdatavalid_sam_csr      <= 1'b1;    //readvalid_sam asserts one clock cycle after read asserted.
			end
			else begin
			   avmm_readdatavalid_sam_csr      <= 1'b0;
			end
	   end
   end
	
	always @ (posedge iClk or negedge iRst_n) begin
      if(!iRst_n) begin
		   avmm_readdatavalid_seq_csr         <= 1'b0;
	   end
	  
	   else begin
	      if (avmm_adc_read && (&avmm_adc_byteenable) && seq_csr_addr_range) begin
			   avmm_readdatavalid_seq_csr      <= 1'b1;    //readvalid_seq asserts one clock cycle after read asserted.
			end
			else begin
			   avmm_readdatavalid_seq_csr      <= 1'b0;
			end
	   end
   end

   
////////////////////////////////////////////////////////////
//Instances
////////////////////////////////////////////////////////////

	
adc adc_inst (
		.adc_pll_clock_clk          (iclk_2m_adc),                //    adc_pll_clock.clk
		.adc_pll_locked_export      (iadc_pll_locked),            //   adc_pll_locked.export
		.clock_clk                  (iClk),                       //            clock.clk
		.reset_sink_reset_n         (iRst_n),                     //       reset_sink.reset_n
		.sample_store_csr_address   (sample_store_csr_address),   // sample_store_csr.address
		.sample_store_csr_read      (sample_store_csr_read),      //                 .read
		.sample_store_csr_write     (sample_store_csr_write),     //                 .write
		.sample_store_csr_writedata (sample_store_csr_writedata), //                 .writedata
		.sample_store_csr_readdata  (sample_store_csr_readdata),  //                 .readdata
		.sample_store_irq_irq       (sample_store_irq_irq),       // sample_store_irq.irq
		.sequencer_csr_address      (sequencer_csr_address),      //    sequencer_csr.address
		.sequencer_csr_read         (sequencer_csr_read),         //                 .read
		.sequencer_csr_write        (sequencer_csr_write),        //                 .write
		.sequencer_csr_writedata    (sequencer_csr_writedata),    //                 .writedata
		.sequencer_csr_readdata     (sequencer_csr_readdata)      //                 .readdata
	);


endmodule
